﻿using System.Collections.Generic;
using Tao.OpenGl;
using Tao.Platform.Windows;

namespace proba_pera
{
    public class Visualiser:RwpBaseObject
    {
        /// <summary>
        /// cntrl - ссылка на рабочую область объекта опенгл
        /// list to draw - список юнитов, которые нужно изобразить
        /// startx, starty - координаты начала координат фрейма(экранных координат) относительно координат карты
        /// polywidth, polyheight - ширина полигона
        /// width, height - ширина фрейма в клетках
        /// selectregion coords and enable flag - координаты прямоугольника выбора юнитов и флаг его отрисовки
        /// waylist, waysetted - список вейпоинтов и флаг его наличия
        /// g - графическое ядро
        /// </summary>
        private readonly SimpleOpenGlControl _cntrl;
        private readonly List<RwpUnit> _listToDraw;
        private double _startX;
        private double _startY;
        private double _polyWidth;
        private double _polyHeight;
        int _width, _height;
        private double _selectedRegionStartX, _selectedRegionStartY, _selectedRegionEndX, _selectedRegionEndY;
        private bool _selectedRegionEnabled;
        private List<Waypoint> _wayList;
        private bool _waySetted;
        private GraphicsCore g;

        public Visualiser(SimpleOpenGlControl cntrl, List<RwpUnit> listToDraw, double startx, double starty)
        {
            _cntrl = cntrl;
            g = new GraphicsCore(cntrl);
            _listToDraw = listToDraw;
            _startX = startx;
            _startY = starty;
            _polyWidth = 1.0;
            _polyHeight = 1.0;
            _width = _cntrl.Width/14;
            _height = _cntrl.Height / 14;
            _selectedRegionEnabled = false;
            _selectedRegionStartX = -1; 
            _selectedRegionStartY = -1;
            _selectedRegionEndX = -1;
            _selectedRegionEndY = -1;
        }

        /// <summary>
        /// Отрисовка сетки
        /// </summary>
        private void ShowGrid()
        {
            g.SetColor(0, 125, 0);
            for (int i = 0; i < _width + 1; i++)
            {
                g.Line(i, 1, i, _width);
               
            }
            for (int i = 0; i < _height + 1; i++)
            {
                g.Line(1, i, _width, i);
                Gl.glColor3f(0, 125, 0);
                Gl.glBegin(Gl.GL_LINE_STRIP);
                Gl.glVertex2d(1, i);
                Gl.glVertex2d(_width, i);
                Gl.glEnd();
                Gl.glFlush();
            }
        }

        /// <summary>
        /// Установка пути и флага его наличия
        /// </summary>
        /// <param name="list">Ссылка на список вейпоинтов</param>
        public void SetWay(List<Waypoint> list)
        {
            _wayList = list;
            _waySetted = true;
        }

        /// <summary>
        /// Отмена пути
        /// </summary>
        public void UnsetWay()
        {
            _waySetted = false;
        }

        /// <summary>
        /// Прорисовка пути
        /// </summary>
        public void DrawWay()
        {
            if (_waySetted)
            {
                Gl.glColor3f(0, 100, 100);
                Gl.glBegin(Gl.GL_LINE_STRIP);
                foreach (var waypoint in _wayList)
                {
                    Gl.glVertex2d(waypoint.X+0.5, waypoint.Y+0.5);
                }
                Gl.glEnd();
                Gl.glFlush();
            }
        }

        
        /// <summary>
        /// Выделение области
        /// </summary>
        /// <param name="x1"></param>
        /// <param name="y1"></param>
        /// <param name="x2"></param>
        /// <param name="y2"></param>
        public void SetSelectedRegion(double x1, double y1, double x2, double y2)
        {
            _selectedRegionStartX = x1;
            _selectedRegionStartY = y1;
            _selectedRegionEndX = x2;
            _selectedRegionEndY = y2;
            _selectedRegionEnabled = true;
        }

        /// <summary>
        /// Убрать выделение области
        /// </summary>
        public void UnsetSelectedRegion()
        {
            _selectedRegionStartX = -1;
            _selectedRegionStartY = -1;
            _selectedRegionEndX = -1;
            _selectedRegionEndY = -1;
            _selectedRegionEnabled = false; 
        }

        /// <summary>
        /// Отрисовка выделения области
        /// </summary>
        private void DrawSelectedRegion()
        {
            Gl.glColor3f(0, 0, 0);
            Gl.glBegin(Gl.GL_LINE_LOOP);
            Gl.glVertex2d(_selectedRegionStartX, _selectedRegionStartY);
            Gl.glVertex2d(_selectedRegionEndX, _selectedRegionStartY);
            Gl.glVertex2d(_selectedRegionEndX, _selectedRegionEndY);
            Gl.glVertex2d(_selectedRegionStartX, _selectedRegionEndY);
            Gl.glEnd();
            Gl.glFlush();
        }

        public double GetStartX()
        {
            return _startX;
        }

        public double GetStartY()
        {
            return _startY;
        }

        /// <summary>
        /// Отрисовка модели юнита
        /// </summary>
        /// <param name="unit">Ссылка на экземпляр юнита</param>
        private void DrawModel(RwpUnit unit)
        {
            switch (unit.GetModel())
            {
                case 1:
                    Gl.glColor3f(255, 0, 0);
                    Gl.glBegin(Gl.GL_LINE_LOOP);
                    Gl.glVertex2d(unit.GetX() + 0.1 - _startX, unit.GetY() + 0.1 - _startY);
                    Gl.glVertex2d(unit.GetX() - 0.1 + _polyWidth - _startX, unit.GetY() + 0.1 - _startY);
                    Gl.glVertex2d(unit.GetX() - 0.1 + _polyWidth - _startX, unit.GetY() - 0.1 + _polyHeight - _startY);
                    Gl.glVertex2d(unit.GetX() + 0.1 - _startX, unit.GetY() - 0.1 + _polyHeight - _startY);
                    Gl.glEnd();
                    break;
                case 2:
                    Gl.glColor3f(255, 0, 255);
                    Gl.glBegin(Gl.GL_LINE_LOOP);
                    Gl.glVertex2d(unit.GetX() + 0.1 - _startX, unit.GetY() + 0.1 - _startY);
                    Gl.glVertex2d(unit.GetX() - 0.1 + _polyWidth - _startX, unit.GetY() + 0.1 - _startY);
                    Gl.glVertex2d(unit.GetX() - 0.1 + _polyWidth - _startX, unit.GetY() - 0.1 + _polyHeight - _startY);
                    Gl.glVertex2d(unit.GetX() + 0.1 - _startX, unit.GetY() - 0.1 + _polyHeight - _startY);
                    Gl.glEnd();
                    break;

            }
            //если юнит выбран
            if (unit.Selected)
            {
                Gl.glColor3f(0, 0, 255);
                Gl.glBegin(Gl.GL_LINE_LOOP);
                Gl.glVertex2d(unit.GetX() - _startX, unit.GetY() - _startY);
                Gl.glVertex2d(unit.GetX() + _polyWidth - _startX, unit.GetY() - _startY);
                Gl.glVertex2d(unit.GetX() + _polyWidth - _startX, unit.GetY() + _polyHeight - _startY);
                Gl.glVertex2d(unit.GetX() - _startX, unit.GetY() + _polyHeight - _startY);
                Gl.glEnd();
            }
            Gl.glFlush();         
        }

        /// <summary>
        /// Построение кадра
        /// </summary>
        public void ConstructFrame()
        {
            Gl.glClear(Gl.GL_COLOR_BUFFER_BIT);
            ShowGrid();
            foreach (RwpUnit unit in _listToDraw)
            {
                if (unit.GetX() > _startX && unit.GetX() < _startX + _width && unit.GetY() > _startY && unit.GetY() < _startY + _height)
                {
                    DrawModel(unit);
                }
            }
            if (_waySetted) DrawWay();
            if (_selectedRegionEnabled) DrawSelectedRegion();

            _cntrl.Invalidate();
        }

        /// <summary>
        /// Передвижение экрана
        /// </summary>
        /// <param name="stepX">Сдвиг по горизонтали</param>
        /// <param name="stepY">Сдвиг по вертикали</param>
        public void MoveFrame(double stepX, double stepY)
        {
            _startX += stepX;
            _startY += stepY;
        }

        /// <summary>
        /// Установка размера клетки
        /// </summary>
        /// <param name="newWidth">Ширина</param>
        /// <param name="newHeigth">Высота</param>
        public void SetPolySize(double newWidth, double newHeigth)
        {
            _polyWidth = newWidth;
            _polyHeight = newHeigth;
        }

        /// <summary>
        /// Установка размера фрейма
        /// </summary>
        /// <param name="newWidth">Ширина</param>
        /// <param name="newHeigth">Высота</param>
        public void SetFrameSize(int newWidth, int newHeigth)
        {
            _width = newWidth;
            _height = newHeigth;
        }

        
    }
}